﻿using System;
using System.Collections.Generic;
using System.Linq;
using Bots.DungeonBuddy.Helpers;
using CommonBehaviors.Actions;
using FarmerJoe.ClassSettings;
using FarmerJoe.Helpers;
using FarmerJoe.Helpers.Logging;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Inventory;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace FarmerJoe.Classes
{
    public static class Common
    {
        private static LocalPlayer Me { get { return StyxWoW.Me; } }
        private static WoWUnit CT { get { return Me.CurrentTarget; } }



        public class NeedToRestHeal : Decorator
        {
            public NeedToRestHeal(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                if (Me.IsDead || Me.IsGhost) return false;
                if (Me.HasAura("Life Spirit")) return false;
                if (!Timers.SpellOkToCast("Rest Heal Cast", 800)) return false;
                if (Me.HealthPercent <= ClassParser.RestHealth) return true;

                return false;
            }
        }

        public class RestHeal : Action
        {
            protected override RunStatus Run(object context)
            {
                bool result = false;
                string spellName = "";
                switch (Me.Class)
                {
                        case WoWClass.Druid:
                        if (SpellManager.HasSpell("Healing Touch") && Me.HealthPercent < 60)
                        {
                            spellName = "Healing Touch";
                        }
                        else if (SpellManager.HasSpell("Rejuvenation"))
                        {
                            spellName = "Rejuvenation";
                            break;
                        }

                        break;
                }

                if (spellName != "")
                {
                    Timers.Reset("Rest Heal Cast");
                    result = SpellManager.Cast(spellName, Me);
                    if (result) Log.Write("Rest; casting " + spellName);
                }
                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }

        /*
        public class NeedToUseLifeSpirit : Decorator
        {
            public NeedToUseLifeSpirit(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                
                if (Me.IsDead || Me.IsGhost) return false;
                if (Me.HasAura("Life Spirit")) return false;

                if (Me.HealthPercent > ClassParser.HealthPotion) return false;
                //if (Me.Combat && Me.HealthPercent > ClassParser.HealthPotion) return false;
                //if (!Me.Combat && Me.HealthPercent > ClassParser.RestHealth) return false;

                WoWItem item = Inventory.GetItem("Life Spirit");
                if (item == null) return false;
                if (!Inventory.IsUseable(item)) return false;

                //return Me.HealthPercent <= ClassParser.RestHealth && Inventory.IsUseable(item);
                return true;
            }
        }

        public class UseLifeSpirit : Action
        {
            protected override RunStatus Run(object context)
            {
                Inventory.Use(Inventory.GetItem("Life Spirit"));

                return RunStatus.Failure;
            }
        }

         */



        public static Composite UseHealthManaRegenAgent(double healthPercent, double manaPercent)
        {
            return new PrioritySelector(
                new Decorator( ret => !Me.IsDead && !Me.IsGhost && StyxWoW.Me.HealthPercent <= healthPercent,
                    new PrioritySelector( ctx => FindFirstUsableItemBySpell("Healthstone", "Life Spirit", "Healing Potion"),
                        new Decorator( ret => ret != null,
                            new Sequence(
                                new Action(context => { if (Me.IsCasting) SpellManager.StopCasting(); }),
                                new WaitContinue(2, ret=> !SpellManager.GlobalCooldown, new ActionAlwaysSucceed()),
                                new Action(ret => Log.Write(Colours.InformativeColour, String.Format("Using {0}", ((WoWItem)ret).Name))),
                                new Action(ret => ((WoWItem)ret).UseContainerItem()),
                                Spells.WaitForLagDuration()))
                        )),
                new Decorator(ret => !Me.IsDead && !Me.IsGhost && StyxWoW.Me.ManaPercent <= manaPercent,
                    new PrioritySelector( ctx => FindFirstUsableItemBySpell("Restore Mana","Mana Potion", "Water Spirit"),
                        new Decorator( ret => ret != null,
                            new Sequence(
                                new Action(context => { if (Me.IsCasting) SpellManager.StopCasting(); }),
                                new WaitContinue(2, ret => !SpellManager.GlobalCooldown, new ActionAlwaysSucceed()),
                                new Action(ret => Log.Write(Colours.InformativeColour, String.Format("Using {0}", ((WoWItem)ret).Name))),
                                new Action(ret => ((WoWItem)ret).UseContainerItem()),
                                Spells.WaitForLagDuration()))))
                );
        }

        public static WoWItem FindFirstUsableItemBySpell(params string[] spellNames)
        {
            List<WoWItem> carried = StyxWoW.Me.CarriedItems;
            // Yes, this is a bit of a hack. But the cost of creating an object each call, is negated by the speed of the Contains from a hash set.
            var spellNameHashes = new HashSet<string>(spellNames);

            //Log.Write(Colours.WarningColour,"======= finding first useable item....");

            return (from i in carried
                    let spells = i.ItemSpells
                    where i.ItemInfo != null && spells != null && spells.Count != 0 &&
                          i.Usable &&
                          i.Cooldown == 0 &&
                          i.ItemInfo.RequiredLevel <= StyxWoW.Me.Level &&
                          spells.Any(s => s.IsValid && s.ActualSpell != null && spellNameHashes.Contains(s.ActualSpell.Name))
                    orderby i.ItemInfo.Level descending
                    select i).FirstOrDefault();
        }





        public static Composite RestBehaviour()
        {
            return


                // Don't fucking run the rest behavior (or any other) if we're dead or a ghost. Thats all.
                new Decorator( ret => !StyxWoW.Me.IsDead && !StyxWoW.Me.IsGhost && !StyxWoW.Me.IsCasting && !SpellManager.GlobalCooldown,
                    new PrioritySelector(

                        Spells.WaitForCast(),

                        // Make sure we wait out res sickness if we've been told to
                        /*
                        new Decorator(ret => FpswareSettings.Instance.Druid.WaitForResSickness.Contains("always") && StyxWoW.Me.HasAura("Resurrection Sickness"),
                                      new Action(ret => { })),
                         */

                        new Decorator(ret => Me.IsCasting || Me.IsChanneling, new Action(context => RunStatus.Success)),                        
 
                        // Use Life Spirit (if we have it); herbalism item
                        //new NeedToUseLifeSpirit(new UseLifeSpirit()),
                        UseHealthManaRegenAgent(ClassParser.HealthPotion, ClassParser.ManaPotion),

                        // Class specific rest heal
                        // If we're a healing class there is no need to consider eating. Just heal ourself
                        new NeedToRestHeal(new RestHeal()),

                        // Check if we're allowed to eat (and make sure we have some food.
                        // Only certain classes should be eating, others will heal themself
                        new Decorator(ret => (Me.Class == WoWClass.Warlock || Me.Class == WoWClass.Mage || Me.Class == WoWClass.DeathKnight || Me.Class == WoWClass.Rogue || Me.Class == WoWClass.Hunter || Me.Class == WoWClass.Warrior) &&
                                      !Me.HasAura("Life Spirit") && !StyxWoW.Me.IsSwimming && StyxWoW.Me.HealthPercent <= ClassParser.RestHealth && !StyxWoW.Me.HasAura("Food") && Consumable.GetBestFood(false) != null,
                                      new PrioritySelector(
                                          new Decorator(ret => StyxWoW.Me.IsMoving, new Action(ret => Navigator.PlayerMover.MoveStop())),
                                          new Sequence( new Action(ret => Rest.FeedImmediate())
                                              /*Helpers.Common.CreateWaitForLagDuration()*/))),


                        // Make sure we're a class with mana, if not, just ignore drinking all together!
                        new Decorator(ret =>
                                      !StyxWoW.Me.IsSwimming && (StyxWoW.Me.PowerType == WoWPowerType.Mana || StyxWoW.Me.Class == WoWClass.Druid) && StyxWoW.Me.ManaPercent <= ClassParser.RestMana && !StyxWoW.Me.HasAura("Drink") && Consumable.GetBestDrink(false) != null,
                                      new PrioritySelector(
                                          new Decorator(ret => StyxWoW.Me.IsMoving, new Action(ret => Navigator.PlayerMover.MoveStop())),
                                          new Sequence( new Action(ret => Rest.DrinkImmediate())
                                              /*Helpers.Common.CreateWaitForLagDuration()*/))),

                        // This is to ensure we STAY SEATED while eating/drinking. No reason for us to get up before we have to.
                        new Decorator(ret => (StyxWoW.Me.HasAura("Food") && StyxWoW.Me.HealthPercent < 95) || (StyxWoW.Me.HasAura("Drink") && StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent < 95),
                                      new ActionAlwaysSucceed()),


                        new Decorator(ret => ((StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent <= ClassParser.RestMana) || StyxWoW.Me.HealthPercent <= ClassParser.RestHealth) && !StyxWoW.Me.CurrentMap.IsBattleground,
                                      new Action( ret => Logger.Write("We have no food/drink. Waiting to recover our health/mana back")))
                        ));

        }
    }
}
